#include "TimerQueue.h"

#include <sys/timerfd.h>
#include <cstring>
#include <algorithm>

#include <memory>
#include <iostream>

#include "EventLoop.h"

//  全局函数

int createTimerfd() {
    int fd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
    if (fd < 0) {
        std::cout << "createTimerfd error" << std::endl;
        abort();
    }
    return fd;
}

void readTimerfd(int timerfd) {
    uint64_t data;
    int ret = ::read(timerfd, &data, sizeof(data));
    if (ret != sizeof(data)) {
        std::cout << "read timerfd error" << std::endl;
        abort();
    }
}

timespec howLongFromNow(TimeStamp when) {
    timespec ts;
    int64_t microSeconds = when.getMicroSecondsSinceEpoch() - TimeStamp::now().getMicroSecondsSinceEpoch();
    if (microSeconds < 100) {  // 将 负的 和 太小 的间隔都调整为100
        microSeconds = 100;
    }
    ts.tv_sec = microSeconds / TimeStamp::kMicroSecondsPerSecond;
    ts.tv_nsec = (microSeconds % TimeStamp::kMicroSecondsPerSecond) * 100;
    return ts;
}

void resetTimerfd(int timerfd, TimeStamp when) {
    itimerspec old_value;
    itimerspec new_value;
    bzero(&old_value, sizeof(old_value));
    bzero(&new_value, sizeof(new_value));
    new_value.it_value = howLongFromNow(when);
    int ret = ::timerfd_settime(timerfd, CLOCK_MONOTONIC, &new_value, &old_value);
    if (ret < 0) {
        std::cout << "timerfd_settime error" << std::endl;
        abort();
    }
}

// TimerQueue成员函数

TimerQueue::TimerQueue(EventLoop* loop) :
    loop_(loop),
    timerfdSocket_(createTimerfd()),
    timerfdChannel_(loop, timerfdSocket_.getFd()),
    callingExpiredCallback(false)
    {
        timerfdChannel_.setReadCallback(std::bind(&TimerQueue::handleRead, this));
        timerfdChannel_.enableReading();
    }

TimerQueue::~TimerQueue() {
    for (const Entry& entry : timers_) {
        delete entry.second;
    }
}

TimerId TimerQueue::addTimer(TimerCallback cb, TimeStamp when, double interval) {
    Timer* timer = new Timer(cb, when, interval); 
    TimerId timerId(timer, timer->getSequence());
    loop_->runInLoop(std::bind(&TimerQueue::addTimerInLoop, this, timer));
    return timerId;
}

void  TimerQueue::addTimerInLoop(Timer* timer) {
    loop_->assertInLoopThread();

    bool needResetTimerfd = insert(timer);   
    if (needResetTimerfd) {
        resetTimerfd(timerfdSocket_.getFd(), timer->getExpiration());
    }
}

// 如果需要重新设置timerfd的时间，则返回true
bool TimerQueue::insert(Timer* timer) {
    loop_->assertInLoopThread();

    int ret = false;
    if (timers_.empty() || timer->getExpiration() < timers_.begin()->first) {
        ret = true;
    }
    timers_.insert({timer->getExpiration(), timer});
    activeTimers_.insert({timer, timer->getSequence()});
    return ret; 
}

void TimerQueue::cancleTimer(TimerId timerId) {
    loop_->runInLoop(std::bind(&TimerQueue::cancleTimerInLoop, this, timerId));
}

void TimerQueue::cancleTimerInLoop(TimerId timerId) {
    loop_->assertInLoopThread();

    Timer* timer = timerId.timer_;
    int64_t sequence = timerId.sequence_;
    
    Entry entry{timer->getExpiration(), timer};
    TimerIdPair timerIdPair{timer, sequence};

    timers_.erase(entry);
    if (activeTimers_.find(timerIdPair) != activeTimers_.end() && callingExpiredCallback == true) {
        cancleTimers_.insert(timerIdPair);
    } else {
        activeTimers_.erase(timerIdPair);
        delete timerId.timer_;
    }
}

void TimerQueue::handleRead() {
    loop_->assertInLoopThread();

    readTimerfd(timerfdSocket_.getFd());
    TimeStamp now = TimeStamp::now();
    std::vector<Entry> expiredList = getExpried(now);

    cancleTimers_.clear();

    callingExpiredCallback = true;
    for (Entry& entry : expiredList) {
        entry.second->run();
    }
    callingExpiredCallback = false;

    reset(expiredList, now);
}

std::vector<TimerQueue::Entry> TimerQueue::getExpried(TimeStamp now) {
    loop_->assertInLoopThread();
    
    Entry expiredEndEntry{now, reinterpret_cast<Timer*>(UINTPTR_MAX)};
    auto end = timers_.lower_bound(expiredEndEntry);
    
    std::vector<Entry> expiredList;
    std::copy(timers_.begin(), end, std::back_inserter(expiredList));
    
    timers_.erase(timers_.begin(), end);
    for (Entry& entry : expiredList) {
        TimerIdPair timerIdPair{entry.second, entry.second->getSequence()};
        activeTimers_.erase(timerIdPair);
    }
    
    return expiredList;
}

void TimerQueue::reset(std::vector<Entry>& expiredList, TimeStamp now) {
    loop_->assertInLoopThread();
    for (Entry& entry : expiredList) {
        Timer* timer = entry.second;
        TimerIdPair timerIdPair{timer, timer->getSequence()};
        if (timer->isRepeat() && cancleTimers_.find(timerIdPair) == cancleTimers_.end()) {
            timer->restart(now);
            insert(timer);
        } else {
            delete timer;
        }       
    }

    if (timers_.size()) {
        TimeStamp nextExpired = timers_.begin()->second->getExpiration();
        resetTimerfd(timerfdSocket_.getFd(), nextExpired);
    }
}